package cn.com.libertymutual.sys.quartz.config;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration("quartzConfig")
public class QuartzConfig {
	/*//@Value("${quartz.scheduler.instanceName}")
    private String quartzInstanceName;
     
    //@Value("${org.quartz.dataSource.myDS.driver}")
    private String myDSDriver;
     
    //@Value("${org.quartz.dataSource.myDS.URL}")
    private String myDSURL;
     
   // @Value("${org.quartz.dataSource.myDS.user}")
    private String myDSUser;
     
    //@Value("${org.quartz.dataSource.myDS.password}")
    private String myDSPassword;
     
   // @Value("${org.quartz.dataSource.myDS.maxConnections}")
    private String myDSMaxConnections;*/
    
    @Resource
    private QuartzProperties properties;
    
    /**
     * 设置属性
     * @return
     * @throws IOException
     */
    private Properties quartzProperties() throws IOException {
        Properties prop = new Properties();

        QuartzSchedulerProperties scheduler = properties.getScheduler();
        QuartzJobStoreProperties jobStore = properties.getJobStore();
        QuartzThreadPoolProperties threadPool = properties.getThreadPool();
        QuartzPluginProperties plugin = properties.getPlugin();
        
        prop.put("quartz.scheduler.instanceName", scheduler.getInstanceName());
        prop.put("org.quartz.scheduler.instanceName", scheduler.getInstanceName());
        
        prop.put("org.quartz.scheduler.instanceId", scheduler.getInstanceId());
        prop.put("org.quartz.scheduler.skipUpdateCheck", scheduler.getSkipUpdateCheck());
        prop.put("org.quartz.scheduler.jmx.export", scheduler.getJmxExport());
         
        prop.put("org.quartz.jobStore.class", jobStore.getClassName());
        prop.put("org.quartz.jobStore.driverDelegateClass", jobStore.getDriverDelegateClass());
        ///prop.put("org.quartz.jobStore.dataSource", "quartzDataSource");
        prop.put("org.quartz.jobStore.tablePrefix", jobStore.getTablePrefix());
        prop.put("org.quartz.jobStore.isClustered", jobStore.isClustered());
         
        prop.put("org.quartz.jobStore.clusterCheckinInterval", jobStore.getClusterCheckinInterval());
        
        //prop.put("org.quartz.jobStore.dataSource", "myDS");
        
        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", jobStore.getMaxMisfiresToHandleAtATime());
        prop.put("org.quartz.jobStore.misfireThreshold", jobStore.getMisfireThreshold());
        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", jobStore.isTxIsolationLevelSerializable());
        prop.put("org.quartz.jobStore.selectWithLockSQL", jobStore.getSelectWithLockSQL());
        
        prop.put("org.quartz.threadPool.class", threadPool.getClassName());
        prop.put("org.quartz.threadPool.threadCount", threadPool.getThreadCount());
        prop.put("org.quartz.threadPool.threadPriority", threadPool.getThreadPriority());
        prop.put("org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread", threadPool.getThreadsInheritContextClassLoaderOfInitializingThread());
         
        /** 使用系统的，不需要再次创建
        prop.put("org.quartz.dataSource.myDS.driver", myDSDriver);
        prop.put("org.quartz.dataSource.myDS.URL", myDSURL);
        prop.put("org.quartz.dataSource.myDS.user", myDSUser);
        prop.put("org.quartz.dataSource.myDS.password", myDSPassword);
        System.out.println("myDSMaxConnections:" + myDSMaxConnections);
        prop.put("org.quartz.dataSource.myDS.maxConnections", myDSMaxConnections);
        **/
         
        prop.put("org.quartz.plugin.triggHistory.class", plugin.getTriggHistoryClass());
        prop.put("org.quartz.plugin.shutdownhook.class", plugin.getShutdownhookClass());
        prop.put("org.quartz.plugin.shutdownhook.cleanShutdown", plugin.getShutdownhookCleanShutdown());
        return prop;
    }
     
    @Bean(destroyMethod="destroy")
    public SchedulerFactoryBean schedulerFactoryBean(@Qualifier("dialogJobTrigger") Trigger cronJobTrigger, @Qualifier("writeDataSource") DataSource dataSource ) throws IOException { 
        SchedulerFactoryBean factory = new SchedulerFactoryBean(); 
        // this allows to update triggers in DB when updating settings in config file: 
        //用于quartz集群,QuartzScheduler 启动时更新己存在的Job，这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 
        factory.setOverwriteExistingJobs(true); 
        //用于quartz集群,加载quartz数据源 
        //factory.setDataSource(dataSource);   
        //QuartzScheduler 延时启动，应用启动完10秒后 QuartzScheduler 再启动 
        factory.setStartupDelay(10);
        //用于quartz集群,加载quartz数据源配置 
        factory.setQuartzProperties(quartzProperties());
        factory.setAutoStartup(true);
        //factory.setApplicationContextSchedulerContextKey("applicationContext");
        factory.setApplicationContextSchedulerContextKey("applicationContext");
        factory.setDataSource(dataSource);
        //factory.setWaitForJobsToCompleteOnShutdown(waitForJobsToCompleteOnShutdown);
        //注册触发器
        factory.setTriggers( cronJobTrigger );	//直接使用配置文件
//        factory.setConfigLocation(new FileSystemResource(this.getClass().getResource("/quartz.properties").getPath()));
        return factory; 
    }
     
     
    /**
     * 加载job
     * @return
     */
    @Bean("autoScoreTaskJobDetail")
    public JobDetailFactoryBean autoScoreTaskJobDetail() {

        return createJobDetail(InvokingJobDetailDetailFactory.class, properties.getTaskObject().getName(), properties.getTaskObject().getGroupName(), properties.getTaskObject().getTargetObject(), properties.getTaskObject().getMethodName());
    }
 
    /**
     * 加载触发器
     * @param jobDetail
     * @return
     */
    @Bean(name = "dialogJobTrigger")
    public CronTriggerFactoryBean dialogStatusJobTrigger(@Qualifier("autoScoreTaskJobDetail") JobDetail jobDetail) { 
        return dialogStatusTrigger(jobDetail, properties.getTaskObject().getCronExpression());//0 0 1 * * ?
    	
    	//20秒执行一次*/20 * * * * ?
    	///return dialogStatusTrigger(jobDetail, "*/20 * * * * ?");//0 0 1 * * ?
    	
    }
 
    /**
     * 创建job工厂
     * @param jobClass
     * @param groupName
     * @param targetObject
     * @return
     */
    private static JobDetailFactoryBean createJobDetail(Class<? extends Job> jobClass, String name, String groupName, String targetObject, String methodObject) { 
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean(); 
        factoryBean.setJobClass(jobClass); 
        factoryBean.setDurability(true); 
        factoryBean.setRequestsRecovery(true);
        factoryBean.setGroup(groupName);
        factoryBean.setName(name);
        Map<String, String> map = new HashMap<>();
        map.put("targetObject", targetObject);
        map.put("targetMethod", methodObject);
        factoryBean.setJobDataAsMap(map);
        return factoryBean; 
    } 
 
    /**
     * 创建触发器工厂
     * @param jobDetail
     * @param cronExpression
     * @return
     */
    private static CronTriggerFactoryBean dialogStatusTrigger(JobDetail jobDetail, String cronExpression) { 
        CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean(); 
        factoryBean.setJobDetail(jobDetail);
        factoryBean.setCronExpression (cronExpression);
        return factoryBean; 
    }
}
